package org.apache.ibatis.common.parsing;

import java.util.Properties;

/**
 * @Name PropertyParser
 * @Description: MyBatis [properties] 属性解析器
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-16 15:49:13
 **/
public class PropertyParser {
    private static final String KEY_PREFFIX = "org.apache.ibatis.common.parsing.PropertyParser.";
    /**
     * 指示是否在占位符上启用默认值的特殊属性键。
     * 默认值为 false（表示禁用占位符上的默认值）
     * 如果指定 true，则可以在占位符上指定键和默认值（例如 $｛db.username:postgres｝）。
     */
    public static final String KEY_ENABLE_DEFAULT_VALUE = KEY_PREFFIX + "enable-default-value";
    private static final String ENABLE_DEFAULT_VALUE = "false";
    /**
     * 为占位符上的键和默认值指定分隔符的特殊属性键。
     * 默认分隔符为 { ':' }。
     */
    public static final String KEY_DEFAULT_VALUE_SEPARATOR = KEY_PREFFIX + "default-value-separator";
    private static final String DEFAULT_VALUE_SEPARATOR = ":";

    private PropertyParser() {
    }

    /**
     * 解析字符串中的占位符，使用 MyBatis [properties] 属性中配置的值进行替换。
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-16 16:12:04
     */
    public static String parse(String content, Properties variables) {
        VariableTokenHandler handler = new VariableTokenHandler(variables);
        GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
        return parser.parse(content);
    }

    /**
     * MyBatis [properties] 属性处理器
     */
    private static class VariableTokenHandler implements TokenHandler {
        // 输入的属性变量
        private final Properties variables;
        // 是否启用默认值
        private final boolean enableDefaultValue;
        // 如果启用了默认值，键和默认值之间的默认分隔符
        private final String defaultValueSeparator;

        private VariableTokenHandler(Properties variables) {
            this.variables = variables;
            // 如果传入的属性中有就以属性中为准，否则设为默认值。此外，默认不支持默认值，除非在属性中用 org.apache.ibatis.parsing.PropertyParser.enable-default-value 修改
            this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE));
            // 默认分隔符为 “：”，除非在属性中用 org.apache.ibatis.parsing.PropertyParser.default-value-separator 修改
            this.defaultValueSeparator = getPropertyValue(KEY_DEFAULT_VALUE_SEPARATOR, DEFAULT_VALUE_SEPARATOR);
        }

        private String getPropertyValue(String key, String defaultValue) {
            return (variables == null) ? defaultValue : variables.getProperty(key, defaultValue);
        }

        /**
         * 解析字符串中的占位符，使用 MyBatis [properties] 属性中配置的值进行替换。
         * 具体实现中，会以 content 作为键,从 variables 找出并返回对应的值。
         * - 如果启用默认值，则 content 形如 "key:defaultValue"。
         * - 如果没有启用默认值，则 content 形如 "key"。
         *
         * @version v1.0.0
         * @author lichao
         * @date 2024-05-16 16:04:22
         */
        @Override
        public String handleToken(String content) {
            if (variables != null) {
                String key = content;
                // 如果启用了默认值，则设置默认值
                if (enableDefaultValue) {
                    final int separatorIndex = content.indexOf(defaultValueSeparator);
                    String defaultValue = null;
                    if (separatorIndex >= 0) {
                        key = content.substring(0, separatorIndex);
                        defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
                    }
                    if (defaultValue != null) return variables.getProperty(key, defaultValue);
                }
                // 尝试寻找非默认的值
                if (variables.contains(key)) return variables.getProperty(key);
            }
            // 如果 variables 为 null，直接返回原样。
            return "${" + content + "}";
        }
    }

}

